
import random
import pygame as pg
from .. import tool
from .. import constants as c

class Car(pg.sprite.Sprite):  # 定义 Car 类，继承自 pygame 的精灵类

    def __init__(self, x, y, map_y):  # 初始化方法，接受 x、y、map_y 三个参数
        pg.sprite.Sprite.__init__(self)  # 调用父类的初始化方法

        rect = tool.GFX[c.CAR].get_rect()  # 获取小车图像的矩形
        width, height = rect.w, rect.h  # 获取图像的宽度和高度
        self.image = tool.get_image(tool.GFX[c.CAR], 0, 0, width, height)  # 获取小车的图像
        self.rect = self.image.get_rect()  # 获取小车图像的矩形
        self.rect.x = x  # 设置小车的 x 坐标
        self.rect.bottom = y  # 设置小车的底部坐标为 y
        self.map_y = map_y  # 设置小车所在地图的 y 坐标
        self.state = c.IDLE  # 设置小车的状态为静止
        self.dead = False  # 设置小车的死亡状态为 False

    def update(self, game_info):  # 更新方法，接受 game_info 参数
        self.current_time = game_info[c.CURRENT_TIME]  # 获取当前游戏时间
        if self.state == c.IDLE:  # 如果小车状态为静止
            pass  # 什么也不做
        elif self.state == c.WALK:  # 如果小车状态为行走
            self.rect.x += 4  # 每帧向右移动4个像素
        if self.rect.x > c.SCREEN_WIDTH:  # 如果小车超出屏幕右侧
            self.dead = True  # 将小车的死亡状态设置为 True

    def setWalk(self):  # 设置小车行走状态的方法
        if self.state == c.IDLE:  # 如果小车状态为静止
            self.state = c.WALK  # 将小车状态设置为行走

    def draw(self, surface):  # 绘制方法，接受 surface 参数
        surface.blit(self.image, self.rect)  # 将小车图像绘制到指定的 surface 上

class Bullet(pg.sprite.Sprite):
    def __init__(self, x, start_y, dest_y, name, damage, ice):
        pg.sprite.Sprite.__init__(self)

        self.name = name
        # 初始化一些属性，包括图像帧、位置、速度、伤害等
        #初始化方法接受 x 坐标、起始 y 坐标、目标 y 坐标、名称、伤害和是否冰冻等参数，然后设置了一些属性。
        self.frames = []
        self.frame_index = 0
        self.load_images()
        self.image = self.frames[self.frame_index]  # 设置当前图像
        self.rect = self.image.get_rect()  # 获取图像矩形
        self.rect.x = x  # 设置 x 坐标
        self.rect.y = start_y  # 设置起始 y 坐标
        self.dest_y = dest_y  # 目标 y 坐标
        self.y_vel = 4 if (dest_y > start_y) else -4  # 根据起始和目标 y 坐标确定 y 轴速度
        self.x_vel = 4  # x 轴速度
        self.damage = damage  # 伤害值
        self.ice = ice  # 是否冰冻状态
        self.state = c.FLY  # 设置状态为飞行
        self.current_time = 0  # 当前时间

    def loadFrames(self, frames, name):
        # 加载图像帧，根据名称从工具中获取相应的图像，并添加到frames列表中
        frame_list = tool.GFX[name]
        if name in tool.PLANT_RECT:# 如果是植物图像
            data = tool.PLANT_RECT[name]
            x, y, width, height = data['x'], data['y'], data['width'], data['height']
        else:
            x, y = 0, 0
            rect = frame_list[0].get_rect()
            width, height = rect.w, rect.h
        
        for frame in frame_list:
            frames.append(tool.get_image(frame, x, y, width, height))
    
    def load_images(self):
        # 加载子弹的飞行帧和爆炸帧
        self.fly_frames = []
        self.explode_frames = []

        fly_name = self.name  # 获取飞行帧的名称
        if self.name == c.BULLET_MUSHROOM:  # 如果是蘑菇子弹
            explode_name = 'BulletMushRoomExplode'  # 设置爆炸帧的名称
        else:
            explode_name = 'PeaNormalExplode'

        self.loadFrames(self.fly_frames, fly_name)  # 加载飞行帧
        self.loadFrames(self.explode_frames, explode_name)  # 加载爆炸帧

        self.frames = self.fly_frames  # 设置当前帧为飞行帧

    def update(self, game_info):
        # 根据游戏信息更新子弹的状态和位置
        self.current_time = game_info[c.CURRENT_TIME]
        if self.state == c.FLY:
            if self.rect.y != self.dest_y:
                self.rect.y += self.y_vel
                if self.y_vel * (self.dest_y - self.rect.y) < 0:
                    self.rect.y = self.dest_y
            self.rect.x += self.x_vel
            if self.rect.x > c.SCREEN_WIDTH:
                self.kill()
        elif self.state == c.EXPLODE:
            if(self.current_time - self.explode_timer) > 500:
                self.kill()

    def setExplode(self):
        # 设置子弹状态为爆炸状态
        self.state = c.EXPLODE
        self.explode_timer = self.current_time
        self.frames = self.explode_frames
        self.image = self.frames[self.frame_index]

    def draw(self, surface):
        # 在屏幕上绘制子弹的图像
        surface.blit(self.image, self.rect)

class Plant(pg.sprite.Sprite):
    def __init__(self, x, y, name, health, bullet_group, scale=1):
        pg.sprite.Sprite.__init__(self)
        
        self.frames = []
        # 初始化一些属性，包括图像帧、位置、名称、健康值、空闲状态等
        self.frame_index = 0
        self.loadImages(name, scale)
        self.frame_num = len(self.frames)
        self.image = self.frames[self.frame_index]
        self.rect = self.image.get_rect()
        self.rect.centerx = x
        self.rect.bottom = y
        
        self.name = name                #植物的名称
        self.health = health            #植物的健康值
        self.state = c.IDLE             #植物的空闲状态
        self.bullet_group = bullet_group#子弹组
        self.can_sleep = False          #判断是否休眠
        self.animate_timer = 0          #植物动作计时
        self.animate_interval = 100     #植物动作间隔
        self.hit_timer = 0              #植物攻击计时

    def loadFrames(self, frames, name, scale, color=c.BLACK):
        # 根据名称加载图像帧，并设置缩放和颜色
        frame_list = tool.GFX[name]
        if name in tool.PLANT_RECT:
            data = tool.PLANT_RECT[name]
            x, y, width, height = data['x'], data['y'], data['width'], data['height']
        else:
            x, y = 0, 0
            rect = frame_list[0].get_rect()
            width, height = rect.w, rect.h

        for frame in frame_list:
            frames.append(tool.get_image(frame, x, y, width, height, color, scale))

    def loadImages(self, name, scale):
        # 加载植物的图像帧
        self.loadFrames(self.frames, name, scale)

    def changeFrames(self, frames):
        # 改变图像帧并修改位置
        self.frames = frames
        self.frame_num = len(self.frames)
        self.frame_index = 0
        
        bottom = self.rect.bottom
        x = self.rect.x
        self.image = self.frames[self.frame_index]
        self.rect = self.image.get_rect()
        self.rect.bottom = bottom
        self.rect.x = x

    def update(self, game_info):
        # 根据游戏信息更新植物的状态和动画
        self.current_time = game_info[c.CURRENT_TIME]
        self.handleState()
        self.animation()
    
    def handleState(self):
        # 处理植物的状态
        if self.state == c.IDLE:
            self.idling()
        elif self.state == c.ATTACK:
            self.attacking()
        elif self.state == c.DIGEST:
            self.digest()

    #分别定义了植物的空闲、攻击和伤害方法。
    def idling(self):
        pass

    def attacking(self):
        pass

    def digest(self):
        pass

    def animation(self):

        if (self.current_time - self.animate_timer) > self.animate_interval:
            self.frame_index += 1
            if self.frame_index >= self.frame_num:
                self.frame_index = 0
            self.animate_timer = self.current_time
        
        self.image = self.frames[self.frame_index]
        if(self.current_time - self.hit_timer) >= 200:
            self.image.set_alpha(255)
        else:
            self.image.set_alpha(192)

    def canAttack(self, zombie):
        # 判断是否可以攻击僵尸
        if (self.state != c.SLEEP and zombie.state != c.DIE and
            self.rect.x <= zombie.rect.right):
            return True
        return False

    def setAttack(self):
        # 设置植物的状态为攻击
        self.state = c.ATTACK

    def setIdle(self):
        # 设置植物的状态为空闲
        self.state = c.IDLE
        self.is_attacked = False

    def setSleep(self):
        # 设置植物的状态为休眠
        self.state = c.SLEEP
        self.changeFrames(self.sleep_frames)

    def setDamage(self, damage, zombie):
        # 设置植物受到伤害
        self.health -= damage
        self.hit_timer = self.current_time
        if self.health == 0:
            self.kill_zombie = zombie

    def getPosition(self):
        # 获取植物的位置
        return self.rect.centerx, self.rect.bottom

class Sun(Plant):
    def __init__(self, x, y, dest_x, dest_y, is_big=True):
        # 初始化方法接受 x 坐标、y 坐标、目的地 x 坐标、目的地 y 坐标和是否是大太阳的布尔值等参数
        if is_big:
            scale = 0.9
            self.sun_value = c.SUN_VALUE
        else:
            scale = 0.6
            self.sun_value = 12
        Plant.__init__(self, x, y, c.SUN, 0, None, scale)
        # 根据是否是大太阳来设置缩放和阳光值，然后调用父类的初始化方法来初始化
        self.move_speed = 1
        self.dest_x = dest_x
        self.dest_y = dest_y
        self.die_timer = 0
        # 设置移动速度、目的地坐标和死亡计时器等属性
    def handleState(self):
        # 处理太阳的状态
        if self.rect.centerx != self.dest_x:
            self.rect.centerx += self.move_speed if self.rect.centerx < self.dest_x else -self.move_speed
        if self.rect.bottom != self.dest_y:
            self.rect.bottom += self.move_speed if self.rect.bottom < self.dest_y else -self.move_speed
        # 如果太阳未到达目的地，则向目的地移动
        if self.rect.centerx == self.dest_x and self.rect.bottom == self.dest_y:
            if self.die_timer == 0:
                self.die_timer = self.current_time
            elif(self.current_time - self.die_timer) > c.SUN_LIVE_TIME:
                self.state = c.DIE
                self.kill()
        # 如果太阳到达目的地，且超过了存活时间，就将其状态设置为死亡并移除
    def checkCollision(self, x, y):
        # 检查碰撞
        if self.state == c.DIE:
            return False
        if(x >= self.rect.x and x <= self.rect.right and
           y >= self.rect.y and y <= self.rect.bottom):
            self.state = c.DIE
            self.kill()
            return True
        return False
        # 如果太阳已经死亡，则返回 False；否则，如果指定的坐标在太阳的范围内，就将其状态设置为死亡并移除，然后返回 True


class SunFlower(Plant):
    def __init__(self, x, y, sun_group):
        # 初始化方法接受 x 坐标、y 坐标和太阳组
        Plant.__init__(self, x, y, c.SUNFLOWER, c.PLANT_HEALTH, None)
        # 调用父类的初始化方法来初始化
        self.sun_timer = 0
        self.sun_group = sun_group
        # 设置太阳计时器和太阳组等属性

    def idling(self):
        # 空闲状态下的行为
        if self.sun_timer == 0:
            self.sun_timer = self.current_time - (c.FLOWER_SUN_INTERVAL - 6000)
        elif (self.current_time - self.sun_timer) > c.FLOWER_SUN_INTERVAL:
            self.sun_group.add(
                Sun(self.rect.centerx, self.rect.bottom, self.rect.right, self.rect.bottom + self.rect.h // 2))
            self.sun_timer = self.current_time
        # 如果太阳计时器为 0，则将其设置为当前时间减去（花朵产生太阳的间隔时间减去 6000）；
        # 否则，如果当前时间减去太阳计时器大于花朵产生太阳的间隔时间，就向太阳组添加一个新的太阳，并更新太阳计时器

class PeaShooter(Plant):#豌豆射手
    def __init__(self, x, y, bullet_group):
        #初始化植物
        Plant.__init__(self, x, y, c.PEASHOOTER, c.PLANT_HEALTH, bullet_group)
        self.shoot_timer = 0
        
    def attacking(self):
        #攻击行为，在一定时间间隔内向子弹组添加一个新的子弹
        if (self.current_time - self.shoot_timer) > 2000:
            self.bullet_group.add(Bullet(self.rect.right, self.rect.y, self.rect.y,
                                    c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False))
            self.shoot_timer = self.current_time

class RepeaterPea(Plant):#双重射手
    def __init__(self, x, y, bullet_group):
        Plant.__init__(self, x, y, c.REPEATERPEA, c.PLANT_HEALTH, bullet_group)
        self.shoot_timer = 0

    def attacking(self):
        if (self.current_time - self.shoot_timer) > 2000:
            self.bullet_group.add(Bullet(self.rect.right, self.rect.y, self.rect.y,
                                    c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False))
            self.bullet_group.add(Bullet(self.rect.right + 40, self.rect.y, self.rect.y,
                                    c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False))
            self.shoot_timer = self.current_time
        #添加了一个额外位置的子弹
class ThreePeaShooter(Plant):#三重射手
    def __init__(self, x, y, bullet_groups, map_y):
        Plant.__init__(self, x, y, c.THREEPEASHOOTER, c.PLANT_HEALTH, None)
        self.shoot_timer = 0
        self.map_y = map_y
        self.bullet_groups = bullet_groups

    def attacking(self):
        if (self.current_time - self.shoot_timer) > 2000:
            offset_y = 9 # modify bullet in the same y position with bullets of other plants
            for i in range(3):
                tmp_y = self.map_y + (i - 1)
                if tmp_y < 0 or tmp_y >= c.GRID_Y_LEN:
                    continue
                dest_y = self.rect.y + (i - 1) * c.GRID_Y_SIZE + offset_y
                self.bullet_groups[tmp_y].add(Bullet(self.rect.right, self.rect.y, dest_y,
                                        c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False))
            self.shoot_timer = self.current_time

class SnowPeaShooter(Plant):#寒冰射手
    def __init__(self, x, y, bullet_group):
        Plant.__init__(self, x, y, c.SNOWPEASHOOTER, c.PLANT_HEALTH, bullet_group)
        self.shoot_timer = 0

    def attacking(self):
        if (self.current_time - self.shoot_timer) > 2000:
            self.bullet_group.add(Bullet(self.rect.right, self.rect.y, self.rect.y,
                                    c.BULLET_PEA_ICE, c.BULLET_DAMAGE_NORMAL, True))
            self.shoot_timer = self.current_time

class WallNut(Plant):#坚果
    def __init__(self, x, y):
        Plant.__init__(self, x, y, c.WALLNUT, c.WALLNUT_HEALTH, None)
        self.load_images()
        self.cracked1 = False
        self.cracked2 = False

    def load_images(self):
        #加载破裂状态的图片，设置了两个标记来表示是否处于破裂状态。
        self.cracked1_frames = []
        self.cracked2_frames = []
        
        cracked1_frames_name = self.name + '_cracked1'
        cracked2_frames_name = self.name + '_cracked2'

        self.loadFrames(self.cracked1_frames, cracked1_frames_name, 1)
        self.loadFrames(self.cracked2_frames, cracked2_frames_name, 1)
    
    def idling(self):
        #根据植物的健康值判断是否需要切换到破裂状态的图片
        if not self.cracked1 and self.health <= c.WALLNUT_CRACKED1_HEALTH:
            self.changeFrames(self.cracked1_frames)
            self.cracked1 = True
        elif not self.cracked2 and self.health <= c.WALLNUT_CRACKED2_HEALTH:
            self.changeFrames(self.cracked2_frames)
            self.cracked2 = True

class CherryBomb(Plant):#樱桃炸弹
    def __init__(self, x, y):
        Plant.__init__(self, x, y, c.CHERRYBOMB, c.WALLNUT_HEALTH, None)
        self.state = c.ATTACK
        self.start_boom = False
        self.bomb_timer = 0
       # 爆炸范围和状态
        self.explode_y_range = 1
        self.explode_x_range = c.GRID_X_SIZE
    
    def setBoom(self):
        #设置樱桃炸弹的爆炸效果
        frame = tool.GFX[c.CHERRY_BOOM_IMAGE]
        rect = frame.get_rect()
        width, height = rect.w, rect.h
                
        old_rect = self.rect
        image = tool.get_image(frame, 0, 0, width, height, c.BLACK, 1)
        self.image = image
        self.rect = image.get_rect()
        self.rect.centerx = old_rect.centerx
        self.rect.centery = old_rect.centery
        self.start_boom = True

    def animation(self):
        #实现了樱桃炸弹的动画效果和爆炸逻辑
        if self.start_boom:
            if self.bomb_timer == 0:
                self.bomb_timer = self.current_time
            elif(self.current_time - self.bomb_timer) > 500:
                self.health = 0
        else:
            if (self.current_time - self.animate_timer) > 100:
                self.frame_index += 1
                if self.frame_index >= self.frame_num:
                    self.setBoom()
                    return
                self.animate_timer = self.current_time
            
            self.image = self.frames[self.frame_index]

class Chomper(Plant):#大嘴花
    def __init__(self, x, y):
        # 初始化函数，调用父类的初始化函数，并设置大嘴花的相关属性
        Plant.__init__(self, x, y, c.CHOMPER, c.PLANT_HEALTH, None)
        self.animate_interval = 250 # 动画间隔
        self.digest_timer = 0 # 消化计时器
        self.digest_interval = 15000# 消化间隔
        self.attack_zombie = None# 攻击的僵尸
        self.zombie_group = None# 僵尸组

    def loadImages(self, name, scale): # 载入图像
        self.idle_frames = [] # 空闲帧
        self.attack_frames = [] # 攻击帧
        self.digest_frames = [] # 消化帧

        idle_name = name # 空闲状态图像名称
        attack_name = name + 'Attack' # 攻击状态图像名称
        digest_name = name + 'Digest' # 消化状态图像名称

        frame_list = [self.idle_frames, self.attack_frames, self.digest_frames] # 帧列表
        name_list = [idle_name, attack_name, digest_name] # 图像名称列表
        scale_list = [1, 1, 1] # 缩放列表
        rect_list = [(0, 0, 100, 114), None, None] # 矩形列表

        for i, name in enumerate(name_list):
            self.loadFrames(frame_list[i], name, scale_list[i])

        self.frames = self.idle_frames

    def canAttack(self, zombie):# 判断是否可以攻击
        if (self.state == c.IDLE and zombie.state != c.DIGEST and
            self.rect.x <= zombie.rect.right and
            (self.rect.right + c.GRID_X_SIZE//3 >= zombie.rect.x)):
            return True
        return False

    def setIdle(self):# 设置为空闲状态
        self.state = c.IDLE
        self.changeFrames(self.idle_frames)

    def setAttack(self, zombie, zombie_group):# 设置为空闲状态
        self.attack_zombie = zombie
        self.zombie_group = zombie_group
        self.state = c.ATTACK
        self.changeFrames(self.attack_frames)

    def setDigest(self):# 设置为消化状态
        self.state = c.DIGEST
        self.changeFrames(self.digest_frames)

    def attacking(self):# 攻击中
        if self.frame_index == (self.frame_num - 3):
            self.zombie_group.remove(self.attack_zombie)
        if (self.frame_index + 1) == self.frame_num:
            self.setDigest()

    def digest(self): # 消化
        if self.digest_timer == 0:
            self.digest_timer = self.current_time
        elif (self.current_time - self.digest_timer) > self.digest_interval:
            self.digest_timer = 0
            self.attack_zombie.kill()
            self.setIdle()

class PuffShroom(Plant):#小喷菇
    def __init__(self, x, y, bullet_group):
        Plant.__init__(self, x, y, c.PUFFSHROOM, c.PLANT_HEALTH, bullet_group)  # 初始化函数，调用父类的初始化函数，并设置喷火菇的相关属性
        self.can_sleep = True  # 可以睡眠
        self.shoot_timer = 0  # 射击计时器

    def loadImages(self, name, scale):  # 载入图像
        self.idle_frames = []  # 空闲帧
        self.sleep_frames = []  # 睡眠帧

        idle_name = name  # 空闲状态图像名称
        sleep_name = name + 'Sleep'  # 睡眠状态图像名称

        frame_list = [self.idle_frames, self.sleep_frames]  # 帧列表
        name_list = [idle_name, sleep_name]  # 图像名称列表

        for i, name in enumerate(name_list):
            self.loadFrames(frame_list[i], name, 1)

        self.frames = self.idle_frames

    def attacking(self):# 攻击中
        if (self.current_time - self.shoot_timer) > 3000:
            self.bullet_group.add(Bullet(self.rect.right, self.rect.y + 10, self.rect.y + 10,
                                    c.BULLET_MUSHROOM, c.BULLET_DAMAGE_NORMAL, True))
            self.shoot_timer = self.current_time

    def canAttack(self, zombie):# 判断是否可以攻击
        if (self.rect.x <= zombie.rect.right and
            (self.rect.right + c.GRID_X_SIZE * 4 >= zombie.rect.x)):
            return True
        return False


class PotatoMine(Plant):  # 土豆地雷
    def __init__(self, x, y):
        Plant.__init__(self, x, y, c.POTATOMINE, c.PLANT_HEALTH, None)  # 初始化函数，调用父类的初始化函数，并设置土豆地雷的相关属性
        self.animate_interval = 300  # 动画间隔
        self.is_init = True  # 是否初始化
        self.init_timer = 0  # 初始化计时器
        self.bomb_timer = 0  # 爆炸计时器
        self.explode_y_range = 0  # 爆炸垂直范围
        self.explode_x_range = c.GRID_X_SIZE // 3 * 2  # 爆炸水平范围

    def loadImages(self, name, scale):  # 载入图像
        self.init_frames = []  # 初始化帧
        self.idle_frames = []  # 空闲帧
        self.explode_frames = []  # 爆炸帧

        init_name = name + 'Init'  # 初始化状态图像名称
        idle_name = name  # 空闲状态图像名称
        explode_name = name + 'Explode'  # 爆炸状态图像名称

        frame_list = [self.init_frames, self.idle_frames, self.explode_frames]  # 帧列表
        name_list = [init_name, idle_name, explode_name]  # 图像名称列表

        for i, name in enumerate(name_list):
            self.loadFrames(frame_list[i], name, 1, c.WHITE)

        self.frames = self.init_frames

    def idling(self):# 等待中
        if self.is_init:
            if self.init_timer == 0:
                self.init_timer = self.current_time
            elif (self.current_time - self.init_timer) > 15000:
                self.changeFrames(self.idle_frames)
                self.is_init = False

    def canAttack(self, zombie):# 判断是否可以攻击
        if (not self.is_init and zombie.rect.right >= self.rect.x and
            (zombie.rect.x - self.rect.x) <= self.explode_x_range):
            return True
        return False

    def attacking(self):# 攻击中
        if self.bomb_timer == 0:
            self.bomb_timer = self.current_time
            self.changeFrames(self.explode_frames)
        elif (self.current_time - self.bomb_timer) > 500:
            self.health = 0

class Squash(Plant):#窝瓜
    def __init__(self, x, y):
        Plant.__init__(self, x, y, c.SQUASH, c.PLANT_HEALTH, None)  # 初始化函数，调用父类的初始化函数，并设置巨型坚果的相关属性
        self.orig_pos = (x, y)  # 初始位置
        self.aim_timer = 0  # 瞄准计时器
        self.squashing = False  # 是否在攻击中

    def loadImages(self, name, scale):  # 载入图像
        self.idle_frames = []  # 空闲帧
        self.aim_frames = []  # 瞄准帧
        self.attack_frames = []  # 攻击帧

        idle_name = name  # 空闲状态图像名称
        aim_name = name + 'Aim'  # 瞄准状态图像名称
        attack_name = name + 'Attack'  # 攻击状态图像名称

        frame_list = [self.idle_frames, self.aim_frames, self.attack_frames]  # 帧列表
        name_list = [idle_name, aim_name, attack_name]  # 图像名称列表

        for i, name in enumerate(name_list):
            self.loadFrames(frame_list[i], name, 1, c.WHITE)

        self.frames = self.idle_frames

    def canAttack(self, zombie):# 判断是否可以攻击
        if (self.state == c.IDLE and self.rect.x <= zombie.rect.right and
            (self.rect.right + c.GRID_X_SIZE >= zombie.rect.x)):
            return True
        return False

    def setAttack(self, zombie, zombie_group):# 设置为攻击状态
        self.attack_zombie = zombie
        self.zombie_group = zombie_group
        self.state = c.ATTACK

    def attacking(self): # 攻击中
        if self.squashing:
            if self.frame_index == 2:
                self.zombie_group.remove(self.attack_zombie)
            if (self.frame_index + 1) == self.frame_num:
                self.attack_zombie.kill()
                self.health = 0
        elif self.aim_timer == 0:
            self.aim_timer = self.current_time
            self.changeFrames(self.aim_frames)
        elif (self.current_time - self.aim_timer) > 1000:
            self.changeFrames(self.attack_frames)
            self.rect.centerx = self.attack_zombie.rect.centerx
            self.squashing = True
            self.animate_interval = 300

    def getPosition(self):# 获取位置
        return self.orig_pos

class Spikeweed(Plant):  # 地刺类，继承自Plant类
    def __init__(self, x, y):  # 初始化方法
        Plant.__init__(self, x, y, c.SPIKEWEED, c.PLANT_HEALTH, None)  # 调用父类初始化方法，设置地刺的属性
        self.animate_interval = 200  # 动画间隔
        self.attack_timer = 0  # 攻击计时器

    def loadImages(self, name, scale):  # 加载图片
        self.loadFrames(self.frames, name, 0.9, c.WHITE)

    def setIdle(self):  # 设置为空闲状态的方法
        print('spikeweed idle')  # 打印地刺空闲状态信息
        self.animate_interval = 200  # 设置动画间隔为200
        self.state = c.IDLE  # 设置状态为IDLE

    def canAttack(self, zombie):  # 判断是否可以攻击的方法
        if (self.rect.x <= zombie.rect.right and  # 如果地刺的x坐标小于等于僵尸的右边缘坐标
            (self.rect.right >= zombie.rect.x)):  # 且地刺的右边缘坐标大于等于僵尸的x坐标
            return True  # 返回True，表示可以攻击
        return False  # 否则返回False，表示不能攻击

    def setAttack(self, zombie_group):  # 设置为攻击状态的方法
        self.zombie_group = zombie_group  # 设置僵尸组
        self.animate_interval = 50  # 设置动画间隔为50
        self.state = c.ATTACK  # 设置状态为ATTACK

    def attacking(self):  # 攻击中的方法
        if (self.current_time - self.attack_timer) > 2000:  # 如果距离上次攻击超过2000毫秒
            self.attack_timer = self.current_time  # 更新攻击计时器
            for zombie in self.zombie_group:  # 遍历僵尸组
                if self.canAttack(zombie):  # 如果地刺可以攻击到僵尸
                    zombie.setDamage(1, False)  # 让僵尸受到1点伤害，不产生硬直效果

class Jalapeno(Plant):  # 火爆辣椒类，继承自Plant类
    def __init__(self, x, y):  # 初始化方法
        Plant.__init__(self, x, y, c.JALAPENO, c.PLANT_HEALTH, None)  # 调用父类初始化方法，设置火爆辣椒的属性
        self.orig_pos = (x, y)  # 记录初始位置
        self.state = c.ATTACK  # 初始状态为ATTACK
        self.start_explode = False  # 是否开始爆炸
        self.explode_y_range = 0  # 爆炸范围在Y轴的距离
        self.explode_x_range = 377  # 爆炸范围在X轴的距离

    def loadImages(self, name, scale):  # 加载图片
        self.explode_frames = []  # 存储爆炸动画的帧列表
        explode_name = name + 'Explode'  # 获取爆炸动画图片的名称
        self.loadFrames(self.explode_frames, explode_name, 1, c.WHITE)  # 加载爆炸动画帧

        self.loadFrames(self.frames, name, 1, c.WHITE)  # 加载普通状态的帧

    def setExplode(self):  # 设置爆炸状态的方法
        self.changeFrames(self.explode_frames)  # 切换为爆炸动画帧
        self.animate_timer = self.current_time  # 更新动画计时器
        self.rect.x = c.MAP_OFFSET_X  # 设置火爆辣椒的X坐标
        self.start_explode = True  # 标记已经开始爆炸

    def animation(self):  # 动画更新方法
        if self.start_explode:  # 如果开始爆炸
            if (self.current_time - self.animate_timer) > 100:  # 如果距离上次动画更新超过100毫秒
                self.frame_index += 1  # 切换到下一帧
                if self.frame_index >= self.frame_num:  # 如果已经到达动画的最后一帧
                    self.health = 0  # 将火爆辣椒的生命值设为0
                    return
                self.animate_timer = self.current_time  # 更新动画计时器
        else:  # 如果还没有开始爆炸
            if (self.current_time - self.animate_timer) > 100:  # 如果距离上次动画更新超过100毫秒
                self.frame_index += 1  # 切换到下一帧
                if self.frame_index >= self.frame_num:  # 如果已经到达动画的最后一帧
                    self.setExplode()  # 设置为爆炸状态
                    return
                self.animate_timer = self.current_time  # 更新动画计时器
        self.image = self.frames[self.frame_index]  # 更新火爆辣椒的图片

    def getPosition(self):  # 获取位置的方法
        return self.orig_pos  # 返回火爆辣椒的初始位置


class ScaredyShroom(Plant):  # 胆小菇类，继承自Plant类
    def __init__(self, x, y, bullet_group):  # 初始化方法
        Plant.__init__(self, x, y, c.SCAREDYSHROOM, c.PLANT_HEALTH, bullet_group)  # 调用父类初始化方法，设置胆小菇的属性
        self.can_sleep = True  # 能否进入睡眠状态
        self.shoot_timer = 0  # 射击计时器
        self.cry_x_range = c.GRID_X_SIZE * 2  # 能够哭泣的距离范围

    def loadImages(self, name, scale):  # 加载图片的方法
        self.idle_frames = []  # 空闲状态帧列表
        self.cry_frames = []  # 哭泣状态帧列表
        self.sleep_frames = []  # 睡眠状态帧列表

        idle_name = name  # 空闲状态图片名称
        cry_name = name + 'Cry'  # 哭泣状态图片名称
        sleep_name = name + 'Sleep'  # 睡眠状态图片名称

        frame_list = [self.idle_frames, self.cry_frames, self.sleep_frames]  # 帧列表
        name_list = [idle_name, cry_name, sleep_name]  # 图片名称列表

        for i, name in enumerate(name_list):  # 遍历图片名称列表
            self.loadFrames(frame_list[i], name, 1, c.WHITE)  # 加载对应状态的图片帧

        self.frames = self.idle_frames  # 初始状态为空闲状态

    def needCry(self, zombie):  # 是否需要哭泣的方法
        if (zombie.state != c.DIE and self.rect.x <= zombie.rect.right and
                self.rect.x + self.cry_x_range > zombie.rect.x):  # 如果僵尸未死亡且在哭泣范围内
            return True
        return False

    def setCry(self):  # 设置为哭泣状态的方法
        self.state = c.CRY  # 设置状态为哭泣
        self.changeFrames(self.cry_frames)  # 切换为哭泣状态的图片帧

    def setAttack(self):  # 设置为攻击状态的方法
        self.state = c.ATTACK  # 设置状态为攻击
        self.changeFrames(self.idle_frames)  # 切换为空闲状态的图片帧

    def setIdle(self):  # 设置为空闲状态的方法
        self.state = c.IDLE  # 设置状态为空闲
        self.changeFrames(self.idle_frames)  # 切换为空闲状态的图片帧

    def attacking(self):  # 攻击方法
        if (self.current_time - self.shoot_timer) > 2000:  # 如果距离上次攻击超过2000毫秒
            self.bullet_group.add(Bullet(self.rect.right, self.rect.y + 40, self.rect.y + 40,
                                         c.BULLET_MUSHROOM, c.BULLET_DAMAGE_NORMAL, True))  # 在胆小菇右侧生成子弹
            self.shoot_timer = self.current_time  # 更新射击计时器


class SunShroom(Plant):  # 阳光菇类，继承自Plant类
    def __init__(self, x, y, sun_group):  # 初始化方法
        Plant.__init__(self, x, y, c.SUNSHROOM, c.PLANT_HEALTH, None)  # 调用父类初始化方法，设置阳光菇的属性
        self.can_sleep = True  # 能否进入睡眠状态
        self.animate_interval = 200  # 动画间隔时间
        self.sun_timer = 0  # 产生太阳的计时器
        self.sun_group = sun_group  # 太阳组
        self.is_big = False  # 是否已经变大
        self.change_timer = 0  # 变大计时器

    def loadImages(self, name, scale):  # 加载图片的方法
        self.idle_frames = []  # 空闲状态帧列表
        self.big_frames = []  # 变大状态帧列表
        self.sleep_frames = []  # 睡眠状态帧列表

        idle_name = name  # 空闲状态图片名称
        big_name = name + 'Big'  # 变大状态图片名称
        sleep_name = name + 'Sleep'  # 睡眠状态图片名称

        frame_list = [self.idle_frames, self.big_frames, self.sleep_frames]  # 帧列表
        name_list = [idle_name, big_name, sleep_name]  # 图片名称列表

        for i, name in enumerate(name_list):  # 遍历图片名称列表
            self.loadFrames(frame_list[i], name, 1, c.WHITE)  # 加载对应状态的图片帧

        self.frames = self.idle_frames  # 初始状态为空闲状态

    def idling(self):  # 处理空闲状态的方法
        if not self.is_big:  # 如果尚未变大
            if self.change_timer == 0:  # 如果变大计时器为0
                self.change_timer = self.current_time  # 设置变大计时器为当前时间
            elif (self.current_time - self.change_timer) > 25000:  # 如果距离上次变大超过25000毫秒
                self.changeFrames(self.big_frames)  # 切换为变大状态的图片帧
                self.is_big = True  # 设置为已变大

        if self.sun_timer == 0:  # 如果产生太阳的计时器为0
            self.sun_timer = self.current_time - (c.FLOWER_SUN_INTERVAL - 6000)  # 设置产生太阳的计时器为当前时间减去（太阳产生间隔时间-6000）
        elif (self.current_time - self.sun_timer) > c.FLOWER_SUN_INTERVAL:  # 如果距离上次产生太阳超过太阳产生间隔时间
            self.sun_group.add(Sun(self.rect.centerx, self.rect.bottom, self.rect.right,  # 在太阳组中添加太阳
                                   self.rect.bottom + self.rect.h // 2, self.is_big))  # 太阳的位置根据阳光菇的大小不同而不同
            self.sun_timer = self.current_time  # 更新产生太阳的计时器为当前时间


class IceShroom(Plant):  # 寒冰菇类，继承自 Plant 类
    def __init__(self, x, y):  # 初始化方法
        Plant.__init__(self, x, y, c.ICESHROOM, c.PLANT_HEALTH, None)  # 调用父类初始化方法，设置寒冰菇的属性
        self.can_sleep = True  # 能否进入睡眠状态
        self.orig_pos = (x, y)  # 原始位置
        self.start_freeze = False  # 是否开始冰冻

    def loadImages(self, name, scale):  # 加载图片的方法
        self.idle_frames = []  # 空闲状态帧列表
        self.snow_frames = []  # 冰雪状态帧列表
        self.sleep_frames = []  # 睡眠状态帧列表
        self.trap_frames = []  # 陷阱状态帧列表

        idle_name = name  # 空闲状态图片名称
        snow_name = name + 'Snow'  # 冰雪状态图片名称
        sleep_name = name + 'Sleep'  # 睡眠状态图片名称
        trap_name = name + 'Trap'  # 陷阱状态图片名称

        frame_list = [self.idle_frames, self.snow_frames, self.sleep_frames, self.trap_frames]  # 帧列表
        name_list = [idle_name, snow_name, sleep_name, trap_name]  # 图片名称列表
        scale_list = [1, 1.5, 1, 1]  # 图片缩放比例列表

        for i, name in enumerate(name_list):  # 遍历图片名称列表
            self.loadFrames(frame_list[i], name, scale_list[i], c.WHITE)  # 加载对应状态的图片帧

        self.frames = self.idle_frames  # 初始状态为空闲状态

    def setFreeze(self):  # 设置冰冻状态的方法
        self.changeFrames(self.snow_frames)  # 切换为冰雪状态的图片帧
        self.animate_timer = self.current_time  # 更新动画计时器为当前时间
        self.rect.x = c.MAP_OFFSET_X  # 设置矩形区域的x坐标
        self.rect.y = c.MAP_OFFSET_Y  # 设置矩形区域的y坐标
        self.start_freeze = True  # 设置为开始冰冻状态

    def animation(self):  # 动画方法
        if self.start_freeze:  # 如果开始冰冻
            if (self.current_time - self.animate_timer) > 500:  # 如果距离上次动画超过500毫秒
                self.frame_index += 1  # 帧索引加1
                if self.frame_index >= self.frame_num:  # 如果帧索引超过帧数
                    self.health = 0  # 设置生命值为0
                    return
                self.animate_timer = self.current_time  # 更新动画计时器为当前时间
        else:
            if (self.current_time - self.animate_timer) > 100:  # 如果距离上次动画超过100毫秒
                self.frame_index += 1  # 帧索引加1
                if self.frame_index >= self.frame_num:  # 如果帧索引超过帧数
                    if self.state == c.SLEEP:  # 如果状态为睡眠状态
                        self.frame_index = 0  # 帧索引设置为0
                    else:
                        self.setFreeze()  # 设置为冰冻状态
                        return
                self.animate_timer = self.current_time  # 更新动画计时器为当前时间
        self.image = self.frames[self.frame_index]  # 设置当前图像为当前帧的图像

    def getPosition(self):  # 获取位置的方法
        return self.orig_pos  # 返回原始位置


class HypnoShroom(Plant):  # 魅惑菇类，继承自 Plant 类
    def __init__(self, x, y):  # 初始化方法
        Plant.__init__(self, x, y, c.HYPNOSHROOM, 1, None)  # 调用父类初始化方法，设置魅惑菇的属性
        self.can_sleep = True  # 能否进入睡眠状态
        self.animate_interval = 200  # 动画间隔，单位为毫秒

    def loadImages(self, name, scale):  # 加载图片的方法
        self.idle_frames = []  # 空闲状态帧列表
        self.sleep_frames = []  # 睡眠状态帧列表

        idle_name = name  # 空闲状态图片名称
        sleep_name = name + 'Sleep'  # 睡眠状态图片名称

        frame_list = [self.idle_frames, self.sleep_frames]  # 帧列表
        name_list = [idle_name, sleep_name]  # 图片名称列表

        for i, name in enumerate(name_list):  # 遍历图片名称列表
            self.loadFrames(frame_list[i], name, 1, c.WHITE)  # 加载对应状态的图片帧

        self.frames = self.idle_frames  # 初始状态为空闲状态


class WallNutBowling(Plant):  # 坚果保龄球类，继承自 Plant 类
    def __init__(self, x, y, map_y, level):  # 初始化方法
        Plant.__init__(self, x, y, c.WALLNUTBOWLING, 1, None)  # 调用父类初始化方法，设置坚果保龄球的属性
        self.map_y = map_y  # 地图上的y坐标
        self.level = level  # 关卡对象
        self.init_rect = self.rect.copy()  # 初始矩形位置
        self.rotate_degree = 0  # 旋转角度
        self.animate_interval = 200  # 动画间隔，单位为毫秒
        self.move_timer = 0  # 移动计时器
        self.move_interval = 70  # 移动间隔，单位为毫秒
        self.vel_x = random.randint(12, 15)  # x轴速度
        self.vel_y = 0  # y轴速度
        self.disable_hit_y = -1  # 禁用击中的y坐标

    def loadImages(self, name, scale):  # 加载图片的方法
        self.loadFrames(self.frames, name, 1, c.WHITE)  # 加载帧

    def idling(self):  # 空闲方法
        if self.move_timer == 0:  # 如果移动计时器为0
            self.move_timer = self.current_time  # 设置移动计时器为当前时间
        elif (self.current_time - self.move_timer) >= self.move_interval:  # 如果当前时间减去移动计时器大于等于移动间隔
            self.rotate_degree = (self.rotate_degree - 30) % 360  # 更新旋转角度
            self.init_rect.x += self.vel_x  # 根据速度移动
            self.init_rect.y += self.vel_y
            self.handleMapYPosition()  # 处理地图上的y坐标位置
            if self.shouldChangeDirection():  # 如果应该改变方向
                self.changeDirection(-1)  # 改变方向
            if self.init_rect.x > c.SCREEN_WIDTH:  # 如果超出屏幕宽度
                self.health = 0  # 设置健康值为0，植物死亡
            self.move_timer += self.move_interval  # 更新移动计时器

    def canHit(self, map_y):  # 是否可以击中的方法
        if self.disable_hit_y == map_y:  # 如果禁用击中的y坐标等于地图上的y坐标
            return False  # 返回False
        return True  # 返回True

    def handleMapYPosition(self):  # 处理地图上的y坐标位置的方法
        _, map_y1 = self.level.map.getMapIndex(self.init_rect.x, self.init_rect.centery)  # 获取地图上的y坐标
        _, map_y2 = self.level.map.getMapIndex(self.init_rect.x, self.init_rect.bottom)
        if self.map_y != map_y1 and map_y1 == map_y2:  # 如果地图上的y坐标不等于map_y并且map_y1等于map_y2
            # 坚果保龄球移到另一行，应修改它属于的植物组
            self.level.plant_groups[self.map_y].remove(self)  # 移除坚果保龄球
            self.level.plant_groups[map_y1].add(self)  # 添加到新的植物组
            self.map_y = map_y1  # 更新地图上的y坐标

    def shouldChangeDirection(self):  # 是否应该改变方向的方法
        if self.init_rect.centery <= c.MAP_OFFSET_Y:  # 如果初始矩形的中心y坐标小于等于地图偏移量
            return True  # 返回True
        elif self.init_rect.bottom + 20 >= c.SCREEN_HEIGHT:  # 如果初始矩形的底部加20大于等于屏幕高度
            return True  # 返回True
        return False  # 返回False

    def changeDirection(self, map_y):  # 改变方向的方法
        if self.vel_y == 0:  # 如果y轴速度为0
            if self.map_y == 0:  # 如果地图上的y坐标等于0
                direc = 1  # 方向为1
            elif self.map_y == (c.GRID_Y_LEN - 1):  # 如果地图上的y坐标等于(格子y长度-1)
                direc = -1  # 方向为-1
            else:
                if random.randint(0, 1) == 0:  # 如果随机数为0
                    direc = 1  # 方向为1
                else:
                    direc = -1  # 方向为-1
            self.vel_y = self.vel_x * direc  # 更新y轴速度
        else:
            self.vel_y = - self.vel_y  # y轴速度取反

        self.disable_hit_y = map_y  # 禁用击中的y坐标为map_y

    def animation(self):  # 动画方法
        if (self.current_time - self.animate_timer) > self.animate_interval:  # 如果当前时间减去动画计时器大于动画间隔
            self.frame_index += 1  # 帧索引加1
            if self.frame_index >= self.frame_num:  # 如果帧索引大于等于帧数量
                self.frame_index = 0  # 重置帧索引
            self.animate_timer = self.current_time  # 更新动画计时器

        image = self.frames[self.frame_index]  # 获取当前帧的图像
        self.image = pg.transform.rotate(image, self.rotate_degree)  # 旋转图像
        # 旋转时必须保持图像的中心位置
        self.rect = self.image.get_rect(center=self.init_rect.center)  # 更新矩形位置


class RedWallNutBowling(Plant):#红色坚果保龄球
    def __init__(self, x, y):
        Plant.__init__(self, x, y, c.REDWALLNUTBOWLING, 1, None)  # 调用Plant类的初始化方法，设置植物的初始属性
        self.orig_y = y  # 记录植物的初始y坐标
        self.explode_timer = 0  # 记录爆炸计时器
        self.explode_y_range = 1  # 爆炸范围的y坐标范围
        self.explode_x_range = c.GRID_X_SIZE  # 爆炸范围的x坐标范围
        self.init_rect = self.rect.copy()  # 记录植物的初始矩形区域
        self.rotate_degree = 0  # 旋转角度
        self.animate_interval = 200  # 动画播放间隔
        self.move_timer = 0  # 移动计时器
        self.move_interval = 70  # 移动间隔
        self.vel_x = random.randint(12, 15)  # x轴方向的速度

    def loadImages(self, name, scale):
        self.idle_frames = []  # 存储静止状态的帧
        self.explode_frames = []  # 存储爆炸状态的帧

        idle_name = name  # 静止状态的图片名称
        explode_name = name + 'Explode'  # 爆炸状态的图片名称

        frame_list = [self.idle_frames, self.explode_frames]  # 帧列表
        name_list = [idle_name, explode_name]  # 图片名称列表

        for i, name in enumerate(name_list):
            self.loadFrames(frame_list[i], name, 1, c.WHITE)  # 加载帧图片

        self.frames = self.idle_frames  # 初始状态为静止状态

    def idling(self):
        if self.move_timer == 0:
            self.move_timer = self.current_time  # 设置移动计时器
        elif (self.current_time - self.move_timer) >= self.move_interval:  # 若移动时间间隔已过
            self.rotate_degree = (self.rotate_degree - 30) % 360  # 旋转角度
            self.init_rect.x += self.vel_x  # 根据速度移动
            if self.init_rect.x > c.SCREEN_WIDTH:  # 若超出屏幕范围
                self.health = 0  # 设置健康值为0，植物死亡
            self.move_timer += self.move_interval  # 更新移动计时器

    def attacking(self):
        if self.explode_timer == 0:
            self.explode_timer = self.current_time  # 设置爆炸计时器
            self.changeFrames(self.explode_frames)  # 切换到爆炸状态的帧
        elif (self.current_time - self.explode_timer) > 500:  # 若爆炸时间超过500ms
            self.health = 0  # 设置健康值为0，植物死亡

    def animation(self):
        if (self.current_time - self.animate_timer) > self.animate_interval:  # 若到达动画播放间隔
            self.frame_index += 1  # 帧索引加1
            if self.frame_index >= self.frame_num:  # 若超出帧数量
                self.frame_index = 0  # 重置帧索引
            self.animate_timer = self.current_time  # 更新动画计时器

        image = self.frames[self.frame_index]  # 获取当前帧的图像
        if self.state == c.IDLE:  # 若为静止状态
            self.image = pg.transform.rotate(image, self.rotate_degree)  # 旋转图像
        else:  # 若为其他状态（爆炸状态）
            self.image = image  # 使用原始图像
        # 必须保持图像的中心位置不变
        self.rect = self.image.get_rect(center=self.init_rect.center)  # 更新图像的矩形区域

    def getPosition(self):
        return (self.rect.centerx, self.orig_y)  # 返回植物的位置坐标